# -*- coding: utf-8 -*-
from typing import Dict, Any, Optional
import requests
from fastapi import HTTPException
import hmac
import hashlib
from minio import Minio
from socketio import AsyncServer
from core.config import settings
from core.logger import log
from services.redis_service import AsyncRedisService
from scheduler.msg_async_sch import MsgAsyncScheduler
from services.wx_chat_messages import create_wx_messages, get_wx_messages_by_session_id
from services.wx_friends_service import get_fd_by_wx_id, set_friends_remark
from services.wx_user_service import get_wx_token_key
from utils.msg_filter_util import filter_msg_by_type, fiter_special_chat
from utils.ollama import generate_description
from utils.rag_api import get_reply_by_rag
from utils.sender_tools import SenderTools
from utils.socket_util import broadcast_message, download_image
from db.models.chat_message import WebHookMessage

def verify_signature(body: dict, secret: str,) -> bool:
    try:
        bases = f"{body['Wxid']}:{body['MessageType']}:{body['Timestamp']}"
    except KeyError as e:
        raise ValueError(f"缺少必要字段: {e}")
    expected = hmac.new(
        key=secret.encode("utf-8"),
        msg=bases.encode("utf-8"),
        digestmod=hashlib.sha256
    ).hexdigest()
    got = str(body.get("Signature", "")).lower()
    return hmac.compare_digest(expected, got)
def _is_group_chat(user_id: Optional[str]) -> bool:
    """
    判断这个用户是不是群聊发送的消息
    """
    if not isinstance(user_id, str):
        return False
    return user_id.endswith("@chatroom")
def _parse_message(msg: Dict[str, Any])->WebHookMessage:
    raw_text = msg["text"]
    from_user = msg["fromUser"]
    from_nick = msg["fromNick"]
    to_user = msg["toUser"]
    msg_id = msg["msgId"]
    msg_type = msg["msgType"]
    create_time = msg["createTime"]
    is_self = msg["IsSelf"]
    group: bool = _is_group_chat(from_user)
    sender_in_group: Optional[str] = None
    text_clean = raw_text
    # 群聊文本通常是 "成员ID:\n正文"
    if group and ":\n" in raw_text:
        try:
            prefix, rest = raw_text.split(":\n", 1)
            sender_in_group = prefix.strip()
            text_clean = rest
        except ValueError:
            sender_in_group = None
            text_clean = raw_text
    msg = {
        "msg_type": msg_type,
        "from_user": from_user,
        "from_nick": from_nick,
        "to_user": to_user,
        "group": group,
        "sender_in_group": sender_in_group,
        "content": text_clean,
        "msg_id":msg_id,
        "create_time":create_time,
        "is_self":is_self
    }
    return WebHookMessage(**msg)

async def config_webhook(key):
    data = {
        "enabled": True,  # 是否启用 webhook
        "url": "http://192.168.1.85:8000/webhook",  # 你的回调地址（供自检/文档）
        "secret": "999222",  # 验签共享密钥
        "includeSelfMessage": True,  # 是否接收自己发出的消息
        "messageTypes": ["*"],  # ["*"] 或具体枚举，如 ["sync_message"]
        "retryCount": 3,  # 平台端或业务端重试策略参考值
        "timeout": 5,  # 业务处理超时时间（秒）
        "timestampSkewSec": 900,  # 允许的时间偏移（秒），推荐 900 = 15 分钟
        "dedupeMax": 5000  # 去重缓存容量（按 newMsgId/msgId 组合）
    }
    url = f"{settings.BASE_URL}/webhook/Config?key={key}"
    res = requests.post(url,json=data)
    log.info(res.text)
    res_json = res.json()
    return  res_json

async def process_message(raw_data:dict,sio:AsyncServer, redis_service:AsyncRedisService, scheduler:MsgAsyncScheduler, sender_tools:SenderTools, minio_client):
    if not verify_signature(raw_data, settings.WEBHOOK_SECRET):
        raise HTTPException(status_code=503, detail="校验失败...")
    # 解析消息
    messages = await _first_process_msg(raw_data,redis_service)

    for msg in messages:
        if not msg.is_self:   # 非自己发送的消息
            log.info(f"消息发送者：{msg.from_user}，消息接收者：{msg.to_user}，消息内容：{msg.content}，消息ID：{msg.msg_id}")
            #将特定的一些消息进行提前处理--> 例如：怎么查不动产----不走模型,直接发送文件
            if await fiter_special_chat(msg.content,msg.from_user,msg.key):
                continue
            wx_fr = await get_fd_by_wx_id(msg.from_user, msg.to_user)   # 获取好友信息
            if "客户" in wx_fr.tags:  # 判断是否是客户
                await _process_custom_msg(msg=msg,sio=sio,redis_service=redis_service,scheduler=scheduler,sender_tools = sender_tools,minio_client=minio_client)
            else:   # 非客户消息
                await _process_general_msg(msg,minio_client)
        else: # 自己发的消息
            await _process_self_msg(msg,sio)


async def _first_process_msg(raw_data:dict[str, Any],redis_service:AsyncRedisService)->list[WebHookMessage]:
    # 解析消息 消息预处理，将消息统一格式
    processed_data = []
    key = await get_wx_token_key(raw_data["Wxid"])
    if not key:
        raise HTTPException(status_code=503, detail="未找到key")
    try:
        messages = raw_data.get("Data").get("messages")
    except AttributeError:
        raise ValueError("消息格式错误")

    for msg in messages:
        webhook_msg = _parse_message(msg)
        webhook_msg.key = key
        # 对消息类型进行过滤（如果不是文本和图片消息，则忽略）
        if await filter_msg_by_type(webhook_msg.msg_type):
            continue

        # 对消息进行去重，防止重启导致重复消息
        if await redis_service.is_duplicate_msg(webhook_msg.from_user, webhook_msg.to_user, webhook_msg.content):
            log.info(f"重复消息，已忽略，消息内容：{webhook_msg.content}，消息ID：{webhook_msg.msg_id}")
            continue

        processed_data.append(webhook_msg)
    return processed_data


async def _process_custom_msg(msg:WebHookMessage,redis_service:AsyncRedisService, scheduler:MsgAsyncScheduler, sender_tools:SenderTools, minio_client:Minio,sio:AsyncServer):
    # 保存接受消息到数据库
    if msg.msg_type == 3:
        # 将图片上传保存到数据库（以url格式保存）
        image_url = await download_image(msg.key, msg.from_user, msg.msg_id, msg.to_user, minio_client)
        await create_wx_messages(msg.from_user, msg.to_user, "接收", image_url, content_type=msg.msg_type)
        await redis_service.set_image_url(image_url, msg.from_user, msg.to_user)
        # 启动监控任务
        await scheduler.start_monitoring_task(msg.from_user, msg.to_user, data_type="image_url", key=msg.key)
        return
    elif msg.msg_type == 1:
        if f"{msg.from_user}:{msg.to_user}" in scheduler.monitoring_states:
            # 停止定时任务
            await scheduler.stop_monitoring_task(msg.from_user, msg.to_user)
            await scheduler.process_list_data(msg.from_user, msg.to_user, data_type="image_url", key=msg.key,next_content=msg.content)
            return
    # 保存接受消息到数据库
    await create_wx_messages(msg.from_user, msg.to_user, "接收", msg.content)
    # 开始回复
    reply = await get_reply_by_rag(msg.content, msg.from_user, msg.to_user)
    if "##" in reply:
        history_msgs = await get_wx_messages_by_session_id(sender_id=msg.from_user, receiver_id=msg.to_user)
        result = await generate_description(history_msgs)
        await set_friends_remark(msg.to_user, msg.from_user, result)
        return
    send = sender_tools.send_wx_message(reply, msg.from_user, msg.key)
    log.info(f"发送结果: {send}")
    await create_wx_messages(msg.to_user, msg.from_user, "回复", reply)
    send_broadcast_data = {
        "device_id": msg.to_user,
        "is_self_message": True,
        "content": reply,
        "wx_id": msg.from_user
    }
    await broadcast_message(sio, send_broadcast_data, room=msg.to_user)

async def _process_general_msg( msg: WebHookMessage,minio_client: Minio):
    # 不是自己发的，也不是客户标签的人发的
    if msg.msg_type == 1:
        await create_wx_messages(msg.from_user, msg.to_user, "接收", msg.content)
    elif msg.msg_type == 3:
        # 首先获取图片二进制数据
        image_url = await download_image(msg.key, msg.from_user, msg.msg_id, msg.to_user, minio_client)
        await create_wx_messages(msg.from_user, msg.to_user, "接收", image_url, content_type=msg.msg_type)
async def _process_self_msg( msg: WebHookMessage,sio:AsyncServer):
        # 自己发的消息
        log.info(f"消息发送者：{msg.from_user}，消息接收者：{msg.to_user}，消息内容：{msg.content}，消息ID：{msg.msg_id}")
        if msg.msg_type == 1:
            broadcast_data = {
                "is_self_message": True,
                "wx_id": msg.to_user,
                "device_id": msg.from_user,
                "content": msg.content,
                "timestamp": msg.create_time,
                "type": msg.msg_type
            }
            await create_wx_messages(msg.from_user, msg.to_user, "回复", msg.content)
            # 广播消息到 WebSocket 设备房间
            await broadcast_message(sio, broadcast_data, room=msg.from_user)